package com.spzx.order.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.spzx.cart.api.RemoteCartService;
import com.spzx.cart.api.domain.CartInfo;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.order.domain.OrderItem;
import com.spzx.order.domain.OrderLog;
import com.spzx.order.domain.form.OrderForm;
import com.spzx.order.enums.OrderStatus;
import com.spzx.order.mapper.OrderItemMapper;
import com.spzx.order.mapper.OrderLogMapper;
import com.spzx.order.vo.TradeVo;
import com.spzx.product.api.RemoteProductSkuService;
import com.spzx.user.api.RemoteUserAddressService;
import com.spzx.user.api.RemoteUserInfoService;
import com.spzx.user.api.domain.UserAddressDto;
import com.spzx.user.api.domain.UserInfoDto;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import com.spzx.order.mapper.OrderInfoMapper;
import com.spzx.order.domain.OrderInfo;
import com.spzx.order.service.IOrderInfoService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 订单Service业务层处理
 *
 * @author atguigu
 * @date 2024-07-02
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements IOrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private OrderLogMapper orderLogMapper;

    @Autowired
    private RemoteCartService cartService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RemoteUserAddressService userAddressService;

    @Autowired
    private RemoteProductSkuService productSkuService;

    // 订单流水号（幂等性校验）
    private static final String TRADE_NO_KEY = "user:tradeNo:";

    @Override
    public List<OrderInfo> selectOrderInfoList(OrderInfo orderInfo) {
//        return orderInfoMapper.selectOrderInfoList(orderInfo);
        return null;
    }

    @Override
    public OrderInfo selectOrderInfoById(Long id) {
        OrderInfo orderInfo = orderInfoMapper.selectById(id);
        LambdaQueryWrapper<OrderItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderItem::getOrderId, id);
        List<OrderItem> orderItems = orderItemMapper.selectList(wrapper);
        orderInfo.setOrderItemList(orderItems);
        return orderInfo;
    }

    @Override
    public TradeVo trade() {
        TradeVo vo = new TradeVo();
        // 远程调用cart服务，获取选中的商品列表
        R<List<CartInfo>> result = cartService.getCartCheckedList(SecurityConstants.INNER);
        if (result == null || result.getCode() == R.FAIL) {
            throw new ServiceException("系统繁忙，请稍后再试");
        }
        List<CartInfo> cartInfos = result.getData();
        if (CollUtil.isEmpty(cartInfos)) {
            throw new ServiceException("购物车无选中商品");
        }
        BigDecimal totalAmount = new BigDecimal(0);
        List<OrderItem> orderItems = new ArrayList<>();
        for (CartInfo item : cartInfos) {
            OrderItem orderItem = new OrderItem();
            BeanUtils.copyProperties(item, orderItem);
            orderItem.setSkuNum(item.getSkuNum().longValue());
            orderItems.add(orderItem);
            totalAmount = totalAmount.add(item.getCartPrice().multiply(BigDecimal.valueOf(item.getSkuNum())));
        }
        String tradeNo = generateTradeNo(SecurityContextHolder.getUserId());
        vo.setTotalAmount(totalAmount);
        vo.setOrderItemList(orderItems);
        vo.setTradeNo(tradeNo);
        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long submitOrder(OrderForm orderForm) {
        Long userId = SecurityContextHolder.getUserId();
        // 1、订单提交的幂等性校验
        submitAgainCheck(orderForm.getTradeNo(), userId);
        // 2、判断订单中的商品内容不能为空
        List<OrderItem> itemList = orderForm.getOrderItemList();
        if (CollUtil.isEmpty(itemList)) throw new ServiceException("订单中的商品内容不能为空，请选择您要购买的物品");
        // 3、校验所选商品的实时价格
        Set<String> skuIds = itemList.stream().map(item -> String.valueOf(item.getSkuId())).collect(Collectors.toSet());
        R<Map<Long, BigDecimal>> priceResult = productSkuService.getSkuPrice(skuIds, SecurityConstants.INNER);
        if (priceResult == null || R.FAIL == priceResult.getCode()) {
            throw new ServiceException("系统繁忙，请稍后再试");
        }
        Map<Long, BigDecimal> prices = priceResult.getData();
        String priceCheckResult = "";
        for (OrderItem orderItem : itemList) {
            if (orderItem.getSkuPrice().compareTo(prices.get(orderItem.getSkuId())) != 0) {
                priceCheckResult += orderItem.getSkuName() + "价格变化了; ";
            }
        }
        if (StringUtils.isNotEmpty(priceCheckResult)) {
            //更新购物车价格
            cartService.updateCartPrice(SecurityConstants.INNER);
            throw new ServiceException(priceCheckResult);
        }
        // TODO：校验库存并锁定库存
        Long orderId = null;
        try {
            // 下单
            orderId = this.saveOrder(orderForm, userId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("下单失败");
        }
        // 删除购物车选项
        cartService.deleteCartCheckedList(SecurityConstants.INNER);
        return orderId;
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = this.getById(orderId);
        List<OrderItem> orderItems = Db.lambdaQuery(OrderItem.class).eq(OrderItem::getOrderId, orderId).list();
        orderInfo.setOrderItemList(orderItems);
        return orderInfo;
    }

    @Override
    public List<OrderInfo> selectUserOrderInfoList(Integer orderStatus) {
        Long userId = SecurityContextHolder.getUserId();
        return orderInfoMapper.selectUserOrderInfoList(orderStatus, userId);
    }

    /**
     * 渲染订单确认页面-生成用户流水号
     *
     * @param userId
     * @return
     */
    private String generateTradeNo(Long userId) {
        //1.构建流水号Key
        String userTradeKey = TRADE_NO_KEY + userId;
        //2.构建流水号value
        String tradeNo = IdUtil.simpleUUID();
        //3.将流水号存入Redis 暂存5分钟
        redisTemplate.opsForValue().set(userTradeKey, tradeNo, 5, TimeUnit.MINUTES);
        return tradeNo;
    }

    /**
     * 提交订单的幂等性校验，判断用户是否重复提交订单，或者订单过期
     *
     * @param tradeNo
     * @param userId
     */
    private void submitAgainCheck(String tradeNo, Long userId) {
        String tradeNoKey = TRADE_NO_KEY + userId;
//        String cacheTradeNo = redisTemplate.opsForValue().get(tradeNoKey);
//        if (StringUtils.isEmpty(cacheTradeNo)) throw new ServiceException("该订单长时间未提交，订单已过期，请重新结算。");
//        if (!tradeNo.equals(cacheTradeNo)) throw new RuntimeException("请勿重复提交订单");
//        redisTemplate.delete(tradeNoKey);
        // 验证和删除key的过程需要保证原子性
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] " +
                "then " +
                "   return redis.call('del', KEYS[1]) " +
                "else" +
                "   return 0 " +
                "end";
        if (redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(tradeNoKey), tradeNo) == 0) {
            throw new RuntimeException("请勿重复提交订单");
        }
    }

    /**
     * 保存订单及详情信息
     *
     * @param orderForm
     * @param userId
     * @return
     */
    public Long saveOrder(OrderForm orderForm, Long userId) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(userId);
        orderInfo.setNickName(SecurityContextHolder.getUserName());
        orderInfo.setOrderNo(orderForm.getTradeNo());
        orderInfo.setOrderStatus(OrderStatus.UN_PAY.getCode());
        orderInfo.setRemark(orderForm.getRemark());
        // 远程调用获取收货人信息
        R<UserAddressDto> result = userAddressService.getUserAddress(
                Long.valueOf(orderForm.getUserAddressId()), SecurityConstants.INNER);
        if (result == null || R.FAIL == result.getCode()) {
            throw new ServiceException("系统繁忙，请稍后再试。");
        }
        UserAddressDto address = result.getData();
        orderInfo.setReceiverName(address.getName());
        orderInfo.setReceiverPhone(address.getPhone());
        orderInfo.setReceiverTagName(address.getTagName());
        orderInfo.setReceiverProvince(address.getProvinceCode());
        orderInfo.setReceiverCity(address.getCityCode());
        orderInfo.setReceiverDistrict(address.getDistrictCode());
        orderInfo.setReceiverAddress(address.getFullAddress());
        // 计算订单总价
        List<OrderItem> orderItemList = orderForm.getOrderItemList();
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (OrderItem item : orderItemList) {
            totalAmount = totalAmount.add(item.getSkuPrice().multiply(BigDecimal.valueOf(item.getSkuNum())));
        }
        orderInfo.setOriginalTotalAmount(totalAmount);
        orderInfo.setTotalAmount(totalAmount);
        orderInfo.setFeightFee(orderForm.getFeightFee());
        this.save(orderInfo);
        // 执行完orderInfo的插入后，执行List<OrderItem>的插入
        orderItemList.forEach(item -> item.setOrderId(orderInfo.getId()));
        Db.saveBatch(orderItemList);
        // 记录订单日志
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(orderInfo.getId());
        orderLog.setProcessStatus(OrderStatus.UN_PAY.getCode());
        orderLog.setNote("提交订单");
        orderLogMapper.insert(orderLog);
        return orderInfo.getId();
    }
}
